﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
using Renci.iRods.Common;
using Renci.iRods.Exceptions;

namespace Renci.iRods.Packets
{
    internal class PacketTypeMetaDataProperty
    {
        public PropertyInfo Property { get; set; }

        public PacketFieldAttribute Field { get; set; }

        public bool IsEnum { get; set; }

        public IDictionary<string, string> EnumValues { get; set; }

        public string ToXmlTextValue(object value)
        {
            if (value == null)
            {
                return string.Empty;
            }

            if (this.Property.PropertyType.IsEnum && this.EnumValues.ContainsKey(value.ToString()))
            {
                return this.EnumValues[value.ToString()];
            }

            if (value.GetType().IsEnum)
            {
                return ((int)value).ToString();
            }

            switch (this.Field.DataType)
            {
                case DataTypes.Binary:
                    return Convert.ToBase64String((byte[])value);
                case DataTypes.Double:
                case DataTypes.Int:
                case DataTypes.Char:
                case DataTypes.String:
                    return value.ToString();
                case DataTypes.PiString:
                    throw new NotImplementedException();
                case DataTypes.Packet:
                    var packet = value as Packet;
                    if (packet == null)
                        throw new IRodsException("Packet value cannot be null.");
                    return packet.ToXml();
                case DataTypes.Any:
                    throw new NotImplementedException();
                case DataTypes.Enum:
                    throw new NotImplementedException();
                default:
                    throw new NotImplementedException();
            }
        }

        public object FromXmlValue(XElement xml)
        {
            if (xml == null)
            {
                return null;
            }

            if (this.Property.PropertyType.IsEnum)
            {
                var enumValue = (from e in this.EnumValues
                                 where e.Value == xml.Value
                                 select e.Key).SingleOrDefault();

                if (enumValue == null)
                {
                    return int.Parse(xml.Value);
                }
                else
                {
                    return Enum.Parse(this.Property.PropertyType, enumValue);
                }
            }
            else if (this.Property.PropertyType == typeof(DateTime))
            {
                return new DateTime(1970, 1, 1, 0, 0, 0, 0).AddSeconds(double.Parse(xml.Value));
            }

            switch (this.Field.DataType)
            {
                case DataTypes.Binary:
                    return Convert.FromBase64String(xml.Value);
                case DataTypes.Double:
                    return double.Parse(xml.Value);
                case DataTypes.Int:
                    return int.Parse(xml.Value);
                case DataTypes.Char:
                    throw new NotImplementedException();
                case DataTypes.String:
                    return xml.Value;
                case DataTypes.PiString:
                    throw new NotImplementedException();
                case DataTypes.Packet:
                    return Packet.Load(xml);
                case DataTypes.Any:
                    throw new NotImplementedException();
                case DataTypes.Enum:
                    throw new NotImplementedException();
                default:
                    throw new NotImplementedException();
            }
        }
    }
}
